package route

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	aichat "goweb/AIchat"
	"goweb/db"
	code "goweb/some_important_code"
	"io"
	"net/http"
	"os"
	"strconv"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
)
var Car_video_chan=make(chan string,1000)

var conns sync.Map
var Msg_chan = make(chan db.Msg, 1000)
func Init_route(r *gin.Engine) {

	r.Static("/static/css", "./static/css")
	r.Static("/static/js", "./static/js")
	r.Static("/static/imag", "./static/imag")
	r.LoadHTMLGlob("./static/html/*")
}
func Login(c *gin.Context) {
	c.HTML(http.StatusOK, "login.html", nil)
}
func Get_Invite_code(c *gin.Context) {
	c.String(http.StatusOK, code.Invite_code)
}
func Register(c *gin.Context) {
	c.HTML(http.StatusOK, "register.html", nil)
}
func Login_POST(c *gin.Context) {
	db.Changes_channel <- db.Info_Json{Online: 0, Offline: 0, Warning: 0, Notification: 0, AI: 0, LostNum: 0, TextToSpeech: 0, LoginNum: 1}
	username := c.PostForm("username")
	passwd := c.PostForm("passwd")
	var parmcode code.Parmcode = code.OK
	if !db.Usersearch(username) {
		parmcode = code.UserNotExiest
		c.JSON(http.StatusOK, gin.H{
			"parmcode": parmcode,
			"msg":      code.Parmcode_map[parmcode],
		})
	} else {
		if db.UserPasswdMatch(username, passwd) {
			parmcode = code.OK
			userjwt, err := code.CreateJWT(username)
			if err != nil {
				parmcode = code.Fail
			}
			c.JSON(http.StatusOK, gin.H{
				"parmcode": parmcode,
				"msg":      code.Parmcode_map[parmcode],
				"jwt":      userjwt,
			})
		} else {
			parmcode = code.PasswdNotMatch
			c.JSON(http.StatusOK, gin.H{
				"parmcode": parmcode,
				"msg":      code.Parmcode_map[parmcode],
			})
		}
	}
}
func Register_POST(c *gin.Context) {
	username := c.PostForm("username")
	passwd1 := c.PostForm("passwd1")
	passwd2 := c.PostForm("passwd2")
	icode := c.PostForm("invite_code")
	var parmcode code.Parmcode = code.OK
	if passwd1 != passwd2 {
		parmcode = code.PasswdNotMatch
	}
	if len(username) < 6 {
		parmcode = code.UserNmeToShort
	}
	if len(username) > 200 {
		parmcode = code.UsernameToLong
	}
	if len(passwd1) < 6 || len(passwd2) < 6 {
		parmcode = code.PasswdToShort
	}
	if len(passwd1) > 22 || len(passwd2) > 22 {
		parmcode = code.PasswdToLong
	}
	if icode != code.Invite_code {
		parmcode = code.InvitecodeError
	}
	if db.Usersearch(username) {
		parmcode = code.UserExiest
	}
	if parmcode == code.OK {
		check := db.InsertUser(username, passwd1)
		if check {
			c.Redirect(http.StatusFound, "/login")
			c.Abort()
		} else {
			parmcode = code.Fail
			c.JSON(http.StatusOK, gin.H{
				"parmcode": parmcode,
				"msg":      code.Parmcode_map[parmcode],
			})
		}
	} else {
		c.JSON(http.StatusOK, gin.H{
			"parmcode": parmcode,
			"msg":      code.Parmcode_map[parmcode],
		})
	}
}
func CheckJWT(c *gin.Context) {
	var isLogin bool = false
	jwt := c.Request.Header.Get("Cookie")
	fmt.Println(jwt)
	username, err := code.ParseJWT(jwt)
	if err == nil {
		isLogin = true
	}
	if isLogin {
		c.Set("username", username)
	} else {
		c.Redirect(http.StatusFound, "/login")
		c.Abort()
	}
}

func Homepage(c *gin.Context) {
	cvalue, _ := c.Get("username")
	uname, _ := cvalue.(string)
	c.HTML(http.StatusOK, "homepage.html", gin.H{
		"invitecode": code.Invite_code,
		"username":   uname,
		"data":       db.GetJson(),
		"date_data":  db.Get_date_data(),
	})
}
func Win_st_q(c *gin.Context) {
	cvalue, _ := c.Get("username")
	uname, _ := cvalue.(string)
	c.HTML(http.StatusOK, "win_st_q.html", gin.H{
		"invitecode": code.Invite_code,
		"username":   uname,
		"classes":    db.Query_class(),
	})
}
func Get_class(c *gin.Context) {
	c.JSON(http.StatusOK, db.Query_class())
}
func Msg_center(c *gin.Context) {
	cvalue, _ := c.Get("username")
	uname, _ := cvalue.(string)
	c.HTML(http.StatusOK, "msg_center.html", gin.H{
		"invitecode": code.Invite_code,
		"username":   uname,
	})
}

func Ai_chat_room(c *gin.Context) {
	cvalue, _ := c.Get("username")
	uname, _ := cvalue.(string)
	c.HTML(http.StatusOK, "ai_chat_room.html", gin.H{
		"invitecode":  code.Invite_code,
		"username":    uname,
		"history_msg": db.Query_ai_chat_history(uname),
	})
}
func Ai_chat(c *gin.Context) {
	var message string
	var question string
	cvalue, _ := c.Get("username")
	uname, _ := cvalue.(string)
	var m map[string]interface{}
	b, _ := c.GetRawData()
	json.Unmarshal(b, &m)
	question = m["message"].(string)
	db.Insert_ai_chat(uname, uname, question, time.Now().Format("2006-01-02 15:04:05"))

	message = aichat.Ai_reply_baidu(question)

	db.Insert_ai_chat(uname, "ai", message, time.Now().Format("2006-01-02 15:04:05"))
	c.JSON(http.StatusOK, gin.H{
		"username": "ai",
		"massage":  message,
		"time":     time.Now().Format("15:04:05"),
	})
}
func Recieve_msg(c *gin.Context) {
	db.Changes_channel <- db.Info_Json{Online: 0, Offline: 0, Warning: 0, Notification: 1, AI: 0, LostNum: 0, TextToSpeech: 0, LoginNum: 0}
	cvalue, _ := c.Get("username")
	uname, _ := cvalue.(string)
	var OK bool = true
	b, _ := c.GetRawData()
	var m db.Msg
	err := json.Unmarshal(b, &m)
	m.Name = uname
	if err != nil {
		OK = false
	}
	if OK {
		c.JSON(http.StatusOK, gin.H{
			"parmcode": code.OK,
			"name":     uname,
		})
	} else {
		c.JSON(http.StatusOK, gin.H{
			"parmcode": code.Fail,
			"msg":      code.Parmcode_map[code.Fail],
			"name":     uname,
		})
	}
	db.Insert_msg(m)
	Msg_chan <- m
	// json_msg, _ := json.Marshal(m)
	// conns.Range(func(key, value interface{}) bool {
	// 	v := value.(*websocket.Conn)
	// 	v.WriteMessage(websocket.TextMessage, json_msg)
	// 	return true
	// })
}

func Msg_sender() {
	for {
		m := <-Msg_chan
		Send_msg(m)
	}
}
func Send_msg(m db.Msg) {
	json_msg, _ := json.Marshal(m)
	conns.Range(func(key interface{}, value interface{}) bool {
		k := key.(*websocket.Conn)
		k.WriteMessage(websocket.TextMessage, json_msg)
		return true
	})
}
func Query_msg(c *gin.Context) {
	msgs := db.Query_msg()
	c.JSON(http.StatusOK, gin.H{
		"parmcode": code.OK,
		"msgs":     msgs,
	})
}

func Audio(c *gin.Context) {
	cvalue, _ := c.Get("username")
	uname, _ := cvalue.(string)
	c.HTML(http.StatusOK, "audio.html", gin.H{
		"invitecode": code.Invite_code,
		"username":   uname,
	})
}

func Car_video(c *gin.Context) {
	cvalue, _ := c.Get("username")
	uname, _ := cvalue.(string)
	c.HTML(http.StatusOK, "car_video.html", gin.H{
		"invitecode": code.Invite_code,
		"username":   uname,
	})
}
func Up_ws(rw http.ResponseWriter, req *http.Request) {
	upGrader := websocket.Upgrader{
		ReadBufferSize:  8192,
		WriteBufferSize: 8192,
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}
	cnn, err := upGrader.Upgrade(rw, req, nil)
	if err != nil {
		return
	}
	conns.Store(cnn, struct{}{})
	defer func() {
		conns.Delete(cnn)
		cnn.Close()
		fmt.Println("websocket closed")
	}()
	for {
		Mtype, Mcontent, err := cnn.ReadMessage()
		if err != nil {
			break
		}
		cnn.WriteMessage(Mtype, Mcontent)
	}
}

func Text_to_speech(c *gin.Context) {
	b, _ := c.GetRawData()
	var m map[string]interface{}
	err := json.Unmarshal(b, &m)
	var OK bool = true
	if err != nil {
		OK = false
	}
	text := m["text"].(string)
	fmt.Println(text)
	audio, err := aichat.Text_to_auduio(text)
	if err != nil {
		OK = false
		fmt.Println(err)
	}
	if OK {

		c.Header("Content-Type", "audio/mp3")
		c.Header("Content-Disposition", "attachment; filename=audio.mp3")
		c.Writer.Write(audio)
	} else {
		c.JSON(http.StatusOK, gin.H{
			"parmcode": code.Fail,
			"msg":      code.Parmcode_map[code.Fail],
		})
	}
}

func Pic_upload(c *gin.Context) {

	db.Changes_channel <- db.Info_Json{Online: 0, Offline: 0, Warning: 1, Notification: 0, AI: 0, LostNum: 0, TextToSpeech: 0, LoginNum: 0}
	file, _ := c.FormFile("file")
	information := c.PostForm("information")
	w_message := c.PostForm("warning_message")
	Mtype := c.PostForm("type")
	Mtype_int, _ := strconv.Atoi(Mtype)
	fmt.Println("information: " + information)
	fmt.Println("warning_message: " + w_message)
	c.SaveUploadedFile(file, "./uploads/"+file.Filename)

	time_now := time.Now().Format("2006-01-02 15:04:05.000")
	db.Save_pic(file.Filename, information, w_message, Mtype_int, time_now)
	var m1 db.Msg
	m1.Msg = information + ";\n事件:" + w_message+"<image:"+file.Filename+">"
	m1.Name = "system"
	m1.Time = time_now
	db.Insert_msg(m1)
	Msg_chan <- m1
	c.String(200, "upload success")
}

func Pic_get(c *gin.Context) {
	filename := c.Query("filename")
	fmt.Println(filename)
	c.Header("Content-Type", "image/jpeg")
	f, err := os.Open("./uploads/" + filename)
	if err != nil {
		fmt.Println(err)
		c.JSON(http.StatusBadRequest, gin.H{"error": "no file"})
		return
	} else {
		defer f.Close()
	}
	io.Copy(c.Writer, f)
	f.Close()
}

func Lost_found_pic_get(c *gin.Context) {
	filename := c.Query("filename")
	fmt.Println(filename)
	c.Header("Content-Type", "image/jpeg")
	f, err := os.Open("./lost_found_pic/" + filename)
	if err != nil {
		fmt.Println(err)
		c.JSON(http.StatusBadRequest, gin.H{"error": "no file"})
		return
	} else {
		defer f.Close()
	}
	io.Copy(c.Writer, f)
	f.Close()
}

func Lost_found_pic_upload(c *gin.Context) {
	file, _ := c.FormFile("itemImage")
	item_name := c.PostForm("itemName")
	found_person_name := c.PostForm("found_person_name")
	itemDescription := c.PostForm("itemDescription")
	itemDate := c.PostForm("itemDate")
	itemTime := c.PostForm("itemTime")
	found_time := itemDate + " " + itemTime
	hasher := md5.New()
	hasher.Write([]byte(time.Now().Format("2006-01-02 15:04:05.000")))
	hash := hasher.Sum(nil)
	hashString := hex.EncodeToString(hash)
	c.SaveUploadedFile(file, "./lost_found_pic/"+hashString+"_"+file.Filename)
	filename := hashString + "_" + file.Filename
	db.Insert_lost_item(item_name, filename, found_person_name, itemDescription, found_time)
	db.Changes_channel <- db.Info_Json{Online: 0, Offline: 0, Warning: 0, Notification: 0, AI: 0, LostNum: 1, TextToSpeech: 0, LoginNum: 0}
	c.String(200, "success")
}

func Lost_and_found(c *gin.Context) {
	cvalue, _ := c.Get("username")
	uname, _ := cvalue.(string)
	c.HTML(http.StatusOK, "lost_and_found.html", gin.H{
		"invitecode": code.Invite_code,
		"username":   uname,
		"lost_items": db.Query_lost_items(),
	})
}

func Library_update(c *gin.Context) {
	student_id := c.PostForm("student_id")
	isbn := c.PostForm("isbn")
	page_num := c.PostForm("page_number")
	page, err := strconv.Atoi(page_num)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"parmcode": code.Fail,
			"msg":      "page number error",
		})
		return
	}
	err=db.Update_library(page, student_id, isbn)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"parmcode": code.Fail,
			"msg":      "update error",
		})
	}
	c.JSON(http.StatusOK, gin.H{
		"parmcode": code.OK,
		"msg":      "update success",
	})
}
func Library_get(c *gin.Context) {
	student_id := c.Query("student_id")
	c.JSON(http.StatusOK, db.Query_library(student_id))
}

